#define _POSIX_C_SOURCE 200112L
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/select.h>
#include <time.h>

#define KB 1024
#define MB (1024 * 1024)
#define PAGE_SIZE 4 * KB
#define GROUP_PAGES 16  // 每组16个连续页

// 内存访问模式类型
typedef enum {
    ACCESS_MODE_PAGE_BY_PAGE,   // 逐页访问
    ACCESS_MODE_GROUPED         // 分组访问
} AccessMode;

// 时间测量函数
long long get_nanos() {
    struct timespec ts;
    clock_gettime(CLOCK_MONOTONIC, &ts);
    return ts.tv_sec * 1000000000LL + ts.tv_nsec;
}

// 内存预热函数
void warmup_memory(char* block, int total_mb) {
    const int total_bytes = total_mb * MB;
    for (int i = 0; i < total_bytes; i += PAGE_SIZE) {
        block[i] = 0; // 确保每个页都被实际分配
    }
}

// 内存访问测试函数
long long memory_access_test(char* block, int total_mb, AccessMode mode) {
    const int total_bytes = total_mb * MB;
    const int iterations = 10; // 重复5次访问以放大时间差异
    long long start, end;

    start = get_nanos();
    for (int iter = 0; iter < iterations; ++iter) {
        if (mode == ACCESS_MODE_PAGE_BY_PAGE) {
            // 模式1：逐页访问（每次间隔4KB）
            for (int i = 0; i < total_bytes; i += PAGE_SIZE) {
                block[i] = (block[i] + 1) % 256;
            }
        } else {
            // 模式2：分组访问（16个连续页为一组）
            for (int base = 0; base < total_bytes; base += GROUP_PAGES * PAGE_SIZE) {
                int addr = base;
                for (int j = 0; j < GROUP_PAGES; j++, addr++) {
                    if (addr >= total_bytes) break;
                    block[addr] = (block[addr] + 1) % 256;
                }
            }
        }
    }
    end = get_nanos();

    return (end - start) / iterations; // 返回单次平均时间
}

int main() {
    printf("Process PID: %d\n", getpid());
    
    // 1. 分配超过物理内存的空间
    const int total_mb = 10239; // 10000MB
    char* block = malloc((size_t)total_mb * MB);
    if (!block) {
        perror("malloc failed");
        return 1;
    }

    // 2. 预热内存（确保所有页都被实际分配）
    printf("Warming up memory...\n");
    warmup_memory(block, total_mb);

    // 3. 执行两种访问模式的测试
    printf("Running page-by-page test...\n");
    long long time_page = memory_access_test(block, total_mb, ACCESS_MODE_PAGE_BY_PAGE);
    
    printf("Running grouped access test...\n");
    long long time_group = memory_access_test(block, total_mb, ACCESS_MODE_GROUPED);

    // 4. 输出结果
    printf("\nResults:\n");
    printf("Page-by-page access time: %lld ns\n", time_page);
    printf("Grouped access time     : %lld ns\n", time_group);

    free(block);
    return 0;
}